﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace KyDependencyPlugin
{
    /// <summary>
    /// 依赖扫描注入帮助类
    /// </summary>
    public static class RegisterHelper
    {
        private static IServiceCollection mservices;

        //根服务
        public static IServiceProvider RootService;
        public static bool IsWeb = false;
        /// <summary>
        /// 获取请求上下文
        /// </summary>
        public static HttpContext? HttpContext => RootService?.GetService<IHttpContextAccessor>()?.HttpContext ?? null;

        /// <summary>
        /// 根据文件夹扫描需要自动注册的程序集并注入  默认为根目录
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        public static void AtuoRegister(this IServiceCollection services, IHostBuilder host, bool isWeb = true, string config = "")
        {
            if (mservices != null)
            {
                throw new Exception("Cannot register repeatedly");
            }
            //自定义构造方法
            host.UseServiceProviderFactory(new AOPServiceProxviderFactory());
            IsWeb = isWeb;
            mservices = services;
            if (isWeb)
            {
                RegistHttp();
            }
            IList<Type> list = GetRegisterNamedService(config);
            if (list == null || list.Count <= 0) return;
            Registers(services, list);
        }

        /// <summary>
        /// 控制台程序注册后直接使用
        /// </summary>
        /// <param name="isWeb"></param>
        /// <param name="config"></param>
        public static void AtuoRegisterConsole(bool isWeb = true, string config = "")
        {
            IsWeb = isWeb;
            if (mservices != null)
            {
                throw new Exception("Cannot register repeatedly");
            }
            mservices = new AOPServiceProxviderFactory().CreateBuilder(new ServiceCollection());
            if (isWeb)
            {
                RegistHttp();
            }
            IList<Type> list = GetRegisterNamedService(config);
            if (list == null || list.Count <= 0) return;
            Registers(mservices, list);
            RootService = new AOPServiceProxviderFactory().CreateServiceProvider(mservices);
        }


        //注册http请求
        private static void RegistHttp()
        {
            mservices.AddHttpContextAccessor();
        }

        /// <summary>
        /// 获取该文件下可以注册的类型
        /// </summary>
        /// <param name="config"></param>
        /// <returns></returns>
        public static IList<Type> GetRegisterNamedService(string config)
        {
            List<Type> lis = new List<Type>();
            DirectoryInfo root = new DirectoryInfo(Path.Combine(AppContext.BaseDirectory, config));
            FileInfo[] files = root.GetFiles();
            if (files == null) return new List<Type>();
            files = files.Where(p => p.Extension == ".dll" && !p.Name.ToLower().StartsWith("system.")).ToArray();
            foreach (var item in files)
            {
                var loadedAssembly = LoadAssembly(item.FullName);
                if (loadedAssembly == default) continue;
                var assembly = new[] { loadedAssembly };

                // 合并程序集
                IList<Type> l = loadedAssembly.GetTypes().Where(p => p.IsClass && !p.IsAbstract && p.IsPublic && p.GetInterfaces().Contains(typeof(IDependency))).ToList();
                if (l.Count > 0)
                {
                    lis.AddRange(l);
                }
            }
            return lis;

        }

        /// <summary>
        /// 根据接口注入class
        /// </summary>
        /// <param name="services">需要注入的容器服务</param>
        /// <param name="interFaceType"></param>
        /// <param name="severtype">继承接口名</param>
        /// <param name="lifeType">生命周期接口 </param>
        private static void RegisterInterFace(IServiceCollection services, Type interFaceType, Type severtype, Type lifeType)
        {

            if (lifeType == typeof(ITransient))
            {
                services.AddTransient(interFaceType, severtype);
            }
            else if (lifeType == typeof(ISingleton))
            {
                services.AddSingleton(interFaceType, severtype);
            }
            else
            {
                services.AddScoped(interFaceType, severtype);
            }
        }
        /// <summary>
        /// 获取请求生存周期的服务
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="serviceProvider"></param>
        /// <returns></returns>
        public static TService GetService<TService>(IServiceProvider serviceProvider = default)
            where TService : class
        {
            return GetService<TService>(serviceProvider) as TService;
        }
        /// <summary>
        ///  注入Calss自己
        /// </summary>
        /// <param name="services">需要注入的容器服务</param>
        /// <param name="severtype">继承接口名</param>
        /// <param name="lifeType">生命周期接口 </param>
        private static void RegisterSelfe(IServiceCollection services, Type severtype, Type lifeType)
        {
            if (lifeType == typeof(ITransient))
            {
                services.AddTransient(severtype);
            }
            else if (lifeType == typeof(ISingleton))
            {
                services.AddSingleton(severtype);
            }
            else
            {
                services.AddScoped(severtype);
            }

        }

        /// <summary>
        /// 根据类型批量注入到容器
        /// </summary>
        /// <param name="services">容器</param>
        /// <param name="lis">类型列表</param>
        private static void Registers(IServiceCollection services, IList<Type> lis)
        {
            var lifetimeInterfaces = new[] { typeof(ITransient), typeof(IScoped), typeof(ISingleton) };
            if (lis.Count <= 0) return;
            foreach (var type in lis)
            {
                Type[] types = type.GetInterfaces();

                if (types == null || types.Length <= 0) continue;
                Type? liftime = types.Where(p => lifetimeInterfaces.Contains(p)).FirstOrDefault();
                if (liftime == null) continue;
                bool registerInsterFace = types.Where(p => (p != typeof(IDependency)) && (p != typeof(ITransient)) && (p != typeof(IScoped)) && (p != typeof(ISingleton))).ToList().Count() > 0;

                foreach (var interfaceType in types)
                {
                    //if (interfaceType.Name == "IDependency")continue;
                    if (registerInsterFace) RegisterInterFace(services, interfaceType, type, liftime);
                    else if (interfaceType != typeof(IDependency)) RegisterSelfe(services, type, liftime);
                }
            }
        }

        /// <summary>
        /// 扫描指定位置程序集
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static Assembly LoadAssembly(string path)
        {
            try
            {
                if (!File.Exists(path)) return default;
                return Assembly.LoadFrom(path);
            }
            catch
            {

                return default;
            }

        }

        /// <summary>
        /// 获取请求生命周期的服务
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        public static TService? GetService<TService>()
            where TService : class
        {
            try
            {
                return GetService(typeof(TService)) as TService;
            }
            catch (Exception ex)
            {

                return null;
            }

        }
        public static IServiceProvider GetServiceProvider(Type serviceType)
        {
            //非web程序不存在Scoped 
            if (!IsWeb)
            {
                return RootService;//
            }
            return GetServiceProviderWeb(serviceType);
        }
        //获取http请求构造器
        private static IServiceProvider GetServiceProviderWeb(Type serviceType)
        {

            bool isContainScope = mservices.Where(u => u.ServiceType == (serviceType.IsGenericType ? serviceType.GetGenericTypeDefinition() : serviceType)).Any(u => u.Lifetime == ServiceLifetime.Scoped);
            if (HttpContext != null && isContainScope) return HttpContext.RequestServices;
            return RootService;
        }
        /// <summary>
        /// 获取请求生命周期的服务
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object? GetService(Type type)
        {
            return GetServiceProvider(type).GetService(type);
        }
        /// <summary>
        /// 获取实例列表
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static IEnumerable<TService> GetServices<TService>()
        {

            return GetServiceProvider(typeof(TService)).GetServices<TService>();
        }
        /// <summary>
        /// 根据类名获取实例
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="name">类名</param>
        /// <returns></returns>
        public static TService GetService<TService>(string name)
        {
            IEnumerable<TService> interfaces = GetServiceProvider(typeof(TService)).GetServices<TService>();
            if (interfaces == null || interfaces.Count() <= 0) return default(TService);
            return interfaces.Where(p => p.GetType().Name == name).FirstOrDefault();
        }

        internal static void UserPorvider(this IServiceProvider provider)
        {
            RootService = provider;
        }
    }





}
